﻿
#pragma execution_character_set("utf-8")
#include "stdafx.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "errdatafilereader.h"

/**
 * @brief RecusionFindFiles  递归读取文件夹下所有文件
 * @param folder    读入的目录
 * @param list      文件列表
 * @param filterSuffix 过滤 如果为 "" 就代表只读取没有后缀名的文件
 * @param enableFilter
 */
void RecusionFindFiles(const QString &folder, QStringList &list,const QString &filterSuffix = "",bool enableFilter = false)
{
    QDir dir(folder);
    if(!dir.exists())
        return;
    QFileInfoList infoList = dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);

    foreach(auto fileinfo , infoList)
    {
        auto name = fileinfo.absoluteFilePath();

        if(fileinfo.isDir() == false)
        {
            //不是文件夹
            if(enableFilter)
            {
                //进行过滤
                if(fileinfo.suffix() == filterSuffix)
                {
                    if(!(fileinfo.baseName().contains("Statis") | fileinfo.baseName().contains("True")))
                        if(ErrDataFileReader::checkErrDataFile(name))
                            list.append(name);
                    //                        else
                    //                            LOG() << name;
                }
            }else //不进行过滤添加到列表
                list.append(name);
        }else
            RecusionFindFiles(name, list, filterSuffix, enableFilter);
    }
}


/**
 * @brief RecusionFindDirs  递归读取文件夹下所有文件夹
 * @param folder    读入的目录
 * @param list      文件夹
 */
// 不包含自身 所以
// 调用前 list.append(QFileInfo(folder).absoluteFilePath());
void RecusionFindDirs(const QString &folder, QStringList &list)
{
    QDir dir(folder);
    if(!dir.exists())
        return;
    QFileInfoList infoList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);

    foreach(auto fileinfo , infoList)
    {
        auto name = fileinfo.absoluteFilePath();

        list.append(name);
        RecusionFindDirs(name, list);
    }
}
static int plWorkMode = 1;
static bool plCheckTF = false;
static bool plCheckTime = false;
static int  plTimeUTCStart = 0;
static int  plTimeUTCEnd = 0;
static QString outputPath = "";
static QString inputPath = "";

QPair<QString,QStringList> dgWorker(const QString & path)
{
    if(plCheckTime)
    {
        auto t = QFileInfo(path).lastModified().toTime_t();
        if(t < plTimeUTCStart | t>plTimeUTCEnd)
            return QPair<QString,QStringList>();
    }

    LOG() << path;
    ErrDataFileReader file(path);
    file.readItems();
    if(plCheckTF)
        file.readTrue();

    return file.saveOutPutFile(plWorkMode,plCheckTF,outputPath,inputPath);
}

void plworker(const QString &path)
{
    QDir dir(path);
    if(!dir.exists())
        return;
    QFileInfoList infoList = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
    QMap<QString,QStringList> reports;
    foreach(auto fileinfo , infoList)
    {
        auto name = fileinfo.absoluteFilePath();

        if(fileinfo.isDir() == false)
        {
            //进行过滤
            if(fileinfo.suffix() == "")
            {
                if(!(fileinfo.baseName().contains("Statis") | fileinfo.baseName().contains("True")))
                    if(ErrDataFileReader::checkErrDataFile(name))
                    {
                        auto res = dgWorker(name);
                        reports[res.first].append(res.second);
                    }
            }
        }
    }

    for(auto it : reports.keys() )
    {
        QFile f(it + "/" + "report.csv");
        if(f.open(QFile::WriteOnly | QFile::Truncate)) {
            QTextStream out(&f);
            //                out << QStringLiteral("文件名,板号,T/B,缺陷序号,缺陷代码,缺陷坐标,缺陷大小,真假") << "\r\n";
            out << QStringLiteral("Filename,PCB Num.,Top or Bottomside,Fault Num.,Fault Code,X Y,Fault Size,Ture or False") << "\r\n";

            for(auto line : reports[it] )
            {
                out << line << "\r\n";
            }
            out.flush();
            f.close();
        }
    }
}

void reportCSV(QMap<QString,QStringList> &reports,const QPair<QString,QStringList> &result)
{
    reports[result.first].append(result.second);
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->dtEnd->setDateTime(QDateTime::currentDateTime());
    ui->DT->setText(QDateTime::currentDateTime().toString());

    auto timer = new QTimer;
    QObject::connect(timer,&QTimer::timeout,[&](){
        ui->DT->setText(QDateTime::currentDateTime().toString());
    });
    timer->start(1000);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setWindowBusy()
{
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    ui->groupBox->setEnabled(false);
    ui->groupBox_2->setEnabled(false);
}

void MainWindow::clearWindowBusy()
{
    QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
    ui->groupBox->setEnabled(true);
    ui->groupBox_2->setEnabled(true);
}


void MainWindow::processingList(QStringList &list,const QString &output)
{
    auto totals = list.size();

    LOG() << "待处理文件夹总数" << totals;

    plProcessingListWatcher = new QFutureWatcher<void>;
    QThreadPool::globalInstance()->setMaxThreadCount(ui->maxThreadCount->value());

    plProcessingListWatcher->setFuture(QtConcurrent::map(list, plworker));

    connect(plProcessingListWatcher,&QFutureWatcher<void>::progressRangeChanged
            ,ui->progressBar,&QProgressBar::setRange);
    connect(plProcessingListWatcher,&QFutureWatcher<void>::progressValueChanged
            ,ui->progressBar,&QProgressBar::setValue);

    connect(plProcessingListWatcher,&QFutureWatcher<void>::progressValueChanged
            ,[totals](int a){LOG() << "当前/总计:" <<a+1 <<"/" <<totals;});

    connect(plProcessingListWatcher,&QFutureWatcher<void>::finished,this,&MainWindow::processOver);
}

void MainWindow::processOver()
{
    LOG() << "完成";
    this->clearWindowBusy();
    if(plProcessingListWatcher)
    {
        //        auto result = plProcessingListWatcher->future().result();

        //        for(auto it : result.keys() )
        //        {
        //            QFile f(it + "/" + "report.csv");
        //            if(f.open(QFile::WriteOnly | QFile::Truncate)) {
        //                QTextStream out(&f);
        //                //                out << QStringLiteral("文件名,板号,T/B,缺陷序号,缺陷代码,缺陷坐标,缺陷大小,真假") << "\r\n";
        //                out << QStringLiteral("Filename,PCB Num.,Top or Bottomside,Fault Num.,Fault Code,X Y,Fault Size,Ture or False") << "\r\n";

        //                for(auto line : result[it] )
        //                {
        //                    out << line << "\r\n";
        //                }
        //                out.flush();
        //                f.close();
        //            }
        //        }
        disconnect(plProcessingListWatcher);
        plProcessingListWatcher->deleteLater();
        plProcessingListWatcher = nullptr;
    }
    if(plCreatListWatcher)
    {
        disconnect(plCreatListWatcher);
        plCreatListWatcher->deleteLater();
        plCreatListWatcher = nullptr;
    }
}

//选择监测文件夹
void MainWindow::on_jcMLXZ_clicked()
{
    auto path = QFileDialog::getExistingDirectory(this,"请选择需要处理的文件夹...","./");
    if(path.isEmpty())
    {
        return;
    }
    else
    {
        ui->jcPath->setText(path);
    }
}


void MainWindow::on_plCL_clicked()
{
    auto path = QFileDialog::getExistingDirectory(this,"请选择需要处理的文件夹...","./");

    if(path.isEmpty())
    {
        return;
    }

    auto outpath = QFileDialog::getExistingDirectory(this,"请选择需要输出的文件夹...","./");
    if(outpath.isEmpty())
    {
        return;
    }

    auto isFilterTrue = ui->plTF->isChecked();
    int saveSet = (ui->plJYT->isChecked() * 1) + (ui->plJQXT->isChecked() * 2) + (ui->plYTBJ->isChecked() * 3);

    outputPath = outpath + "/" + QFileInfo(path).fileName();
    inputPath = path;
    plWorkMode = saveSet;
    plCheckTF = isFilterTrue;
    plCheckTime = ui->plCheckTime->isChecked();
    plTimeUTCEnd = ui->dtEnd->dateTime().toTime_t();
    plTimeUTCStart = ui->dtStart->dateTime().toTime_t();


    plFileList = new QStringList;

    if(plCreatListWatcher != nullptr || plProcessingListWatcher != nullptr)
        return;

    auto future = QtConcurrent::run([this,path](){
        plFileList->append(QFileInfo(path).absoluteFilePath());
        RecusionFindDirs(path,*plFileList);
    });

    setWindowBusy();


    plCreatListWatcher = new QFutureWatcher<void>;

    plCreatListWatcher->setFuture(future);

    connect(plCreatListWatcher,&QFutureWatcher<void>::finished,[this,outpath](){
        processingList(*plFileList,outpath);
    });
}

// 开始监测 / 停止监测
void MainWindow::on_pbJC_clicked()
{
    auto path = ui->jcPath->text();
    const QDir dirw(path);
    if(path.isEmpty() | !dirw.exists())
    {
        return;
    }
    if(m_fileSystemWatcher == nullptr)
    {
        ui->pbJC->setText("停止监测");
        ui->jcJQXT->setEnabled(false);
        ui->jcTF->setEnabled(false);
        ui->jcJYT->setEnabled(false);
        ui->jcYTBJ->setEnabled(false);
        ui->jcPath->setEnabled(false);

        LOG() << "开始监测:" << path;
        m_fileSystemWatcher = new QFileSystemWatcher(this);
        m_fileSystemWatcher->addPath(path);

        //保存当前目录内容列表
        m_currentContentsMap[path] = dirw.entryList(QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Files, QDir::DirsFirst);

        connect(m_fileSystemWatcher,&QFileSystemWatcher::directoryChanged,this,&MainWindow::on_detectedNewFile);

    }else{
        ui->pbJC->setText("开始监测");
        ui->jcJQXT->setEnabled(true);
        ui->jcTF->setEnabled(true);
        ui->jcJYT->setEnabled(true);
        ui->jcYTBJ->setEnabled(true);
        ui->jcPath->setEnabled(true);

        LOG() << "停止监测:" << path;
        m_currentContentsMap.remove(path);

        disconnect(m_fileSystemWatcher);
        m_fileSystemWatcher->deleteLater();
        m_fileSystemWatcher = nullptr;
    }
}

//监测到新的文件产生
void MainWindow::on_detectedNewFile(const QString &path)
{
    QStringList currEntryList = m_currentContentsMap[path];
    const QDir dir(path);
    QStringList newEntryList = dir.entryList(QDir::NoDotAndDotDot  | QDir::AllDirs | QDir::Files, QDir::DirsFirst);

    QSet<QString> newDirSet = QSet<QString>::fromList(newEntryList);
    QSet<QString> currentDirSet = QSet<QString>::fromList(currEntryList);

    QSet<QString> newFiles = newDirSet - currentDirSet;
    QStringList newFile = newFiles.toList();

    auto isCheckTF = !ui->jcTF->isChecked();
    int saveSet = (ui->jcJYT->isChecked() * 1) + (ui->jcJQXT->isChecked() * 2) + (ui->jcYTBJ->isChecked() * 3);

    foreach (auto filename, newFile)
    {
        QFileInfo finfo(path + "/" +filename);
        //目录  有后缀名 或者是合适的数据库文件　添加过滤列表
        if(finfo.isDir() || finfo.suffix() != "" )
        {
            m_currentContentsMap[path].append(filename);
        }else{
            bool hasEr = true;
            if(ErrDataFileReader::blockCheckErrDataFile(finfo.absoluteFilePath(),hasEr,10))
            {
                //如果监测到是需要处理的数据库文件 则检查 True文件是否存在
                //或者没有勾选TF 也开始处理忽略TF文件
                bool hasTrue = QFile::exists(finfo.absoluteFilePath() + "_True");
                if(isCheckTF == false | hasTrue) //如果忽略True文件 则直接处理 否则 数据库和True文件都存在 才处理
                {
                    LOG() << "处理缺陷数据文件:" << isCheckTF << hasTrue << filename;
                    ErrDataFileReader file(finfo.absoluteFilePath());
                    file.readItems();
                    if(isCheckTF)
                        file.readTrue();
                    file.saveOutPutFile(saveSet,isCheckTF);
                    //处理完成后将文件 插入到新文件列表
                    m_currentContentsMap[path].append(filename);
                }
            }else{
                //不是数据库文件 则添加到
                LOG() << "不是数据库文件" << filename;
                m_currentContentsMap[path].append(filename);
            }
        }
    }
}

//void MainWindow::on_commandLinkButton_clicked()
//{
//    QDesktopServices::openUrl(QUrl("http://mfw3d.cn:8080/"));
//}
